package server

import (
	"common_demo/internal/config"
	"common_demo/internal/server/handler"
	"common_demo/internal/server/service"
	"common_demo/pkg/logger"
	"context"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

var server *Server

type Server struct {
	ctx        context.Context
	errCh      chan error
	signalCh   chan os.Signal
	httpServer *http.Server
}

func NewServer(ctx context.Context) error {
	if err := config.LoadConfiguration(ctx); err != nil {
		return err
	}

	if err := logger.InitLogger(config.Config.Logger, logger.WithZapOption(
		zap.AddCaller(),
		zap.AddCallerSkip(1),
		// zap.AddStacktrace(zap.ErrorLevel),
	)); err != nil {
		return err
	}
	defer logger.Sync()

	return newServer(ctx)
}

func newServer(ctx context.Context) error {
	// 注册路由
	ginEngine := gin.Default()
	gin.SetMode(gin.DebugMode)
	service.InitRouter(ginEngine, &service.Logic{Handler: handler.NewServiceHandler(ctx)})

	// 创建server
	server = &Server{
		ctx:      ctx,
		errCh:    make(chan error, 1),
		signalCh: config.SignalCh,
		httpServer: &http.Server{
			Addr:    config.Config.Server.Host,
			Handler: ginEngine,
		},
	}

	// 监听
	signal.Notify(server.signalCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	go server.tcpServe()
	go server.unixServe()

	// 热加载
	for {
		select {
		case err := <-server.errCh:
			return err
		case sig := <-server.signalCh:
			switch sig {
			case syscall.SIGINT, syscall.SIGTERM:
				return server.stop()
			case syscall.SIGHUP:
				server.stop()
				return newServer(ctx)
			}
		case <-ctx.Done():
			return nil
		}
	}
}

// 创建 TCP 监听
func (s *Server) tcpServe() {
	logger.Infof("Starting server on %s", config.Config.Server.Host)
	if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
		s.errCh <- fmt.Errorf("[server.tcpServe]: %s", err.Error())
	}
}

// 创建 UnixSocket 监听
func (s *Server) unixServe() {
	// not implement
}

// 停止服务
func (s *Server) stop() error {
	logger.Infof("Stopping server...")
	ctx, cancel := context.WithTimeout(s.ctx, 5*time.Second)
	defer cancel()
	return s.httpServer.Shutdown(ctx)
}
